
using System;
using System.Text;
using System.Collections.Generic;

namespace MxitAPI {
	
	public delegate void MessageResponseHandler( ProtocolMessage message );
	
	public abstract class MessageTransceiver {
		
		private static log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType );
		
		public MessageTransceiver() {
		}
		
		/**
		 * Sends a ProtocolMessage to the Mxit servers and handles the response
		 */
		public abstract void SendMessage( ProtocolMessage message );
		
		/**
		 * Convert an array of bytes returned by the Mxit server into a string
		 * @param byteArr The array of bytes returned by the Mxit server
		 * @return A string representation of the array of bytes
		 */
		// Todo remove this one
		/*protected string ConvertByteArrayToString( byte[] byteArr ) {

			StringBuilder returnStringBuilder = new StringBuilder();
			for ( int i = 0; i < byteArr.Length; ++i ) {
				returnStringBuilder.Append( Char.ConvertFromUtf32( byteArr[i] ) );
			}
			return returnStringBuilder.ToString();
		}*/
		
		/**
		 * Handles the response returned by the Mxit server for a single protocol message
		 * @param responseString The string for one protocol message response returned from the Mxit server
		 * @param protocolMessage The message that contains the request variables that corrospond to the responseString
		 */
		public void ProcessProtocolMessageResponseString( string responseString, ProtocolMessage protocolMessage ) {
			
			// If the returned message is blank, ignore it
			if ( responseString == String.Empty )
				return;
			
			// Get the method that handles the response for this message, can be null, in which case a response handler will be created
			MessageResponseHandler messageResponseHandler = null;
			if( protocolMessage != null )
				messageResponseHandler = protocolMessage.MessageResponseHandler;
			
			ProtocolMessage returnProtocolMessage = PopulateMessage( responseString, protocolMessage );
			
			// Calls the method that handles the message that has been send from the mxit server
			//for ( int i = 0; i < returnProtocolMessages.Count ; ++i ) {
				// If this is the first response it must match with the request and the handler has been passed in
				if ( messageResponseHandler != null )
					messageResponseHandler( returnProtocolMessage );
				else
					Handler.GetHandler( returnProtocolMessage ).HandleResponseProtocolMessage( returnProtocolMessage );
			//}
		}


		public void ProcessProtocolMessageResponseString( string responseString ) {
			ProcessProtocolMessageResponseString( responseString, null );
		}
		
		
		public void ProcessProtocolMessageResponseString( List<string> responseStrings, ProtocolMessage protocolMessage, MessageResponseHandler messageResponseHandler ) {

            // If there was no response from the mxit server
            if ( responseStrings == null )
                return;

			for ( int i = 0; i < responseStrings.Count; ++i ) {
				if ( i == 0 )
					ProcessProtocolMessageResponseString( responseStrings[i], protocolMessage );
				else
					ProcessProtocolMessageResponseString( responseStrings[i] );
			}
		}
		
		public void ProcessProtocolMessageResponseString( List<string> responseStrings, ProtocolMessage protocolMessage ) {
			for ( int i = 0; i < responseStrings.Count; ++i ) {
				if ( i == 0 )
					ProcessProtocolMessageResponseString( responseStrings[i], protocolMessage );
				else
					ProcessProtocolMessageResponseString( responseStrings[i] );
			}
		}		
		
		public void ProcessProtocolMessageResponseString( List<string> responseStrings ) {
			for ( int i = 0; i < responseStrings.Count; ++i ) {
				if ( i == 0 )
					ProcessProtocolMessageResponseString( responseStrings[i], null );
				else
					ProcessProtocolMessageResponseString( responseStrings[i] );
			}
		}
		
		public ProtocolMessage PopulateMessage( string packet, ProtocolMessage protocolMessage ) {
			
			log.DebugFormat( "Populating a [{0}] message with data [{1}]", protocolMessage, packet.Replace( "\u0000", "!!" ).Replace( "\u000c", "+++" ) );
			
			// If this packet contains chunked binary data
			// Todo get the 27 from the MessageType
			bool isBinaryData = false;
			if( packet.StartsWith( "27" ) )
				isBinaryData = true;

			
			string[] tempOuterStrArr = packet.Split( ( char ) 0 );
			
			ProtocolMessage returnProtocolMessage;
				
			// If the response message is the same command number as the request message, clone the message for the request variables and add the response
			// Todo This is not cloning check it out later
			if ( protocolMessage != null && protocolMessage.ProtocolMessageType == ( ProtocolMessageType ) Int32.Parse( tempOuterStrArr[0] ) )
				returnProtocolMessage = ( ProtocolMessage ) Activator.CreateInstance( protocolMessage.GetType() );
			else {
				returnProtocolMessage = ProtocolMessageCreator.CreateProtocolMessage( Int32.Parse( tempOuterStrArr[0] ) );
				if ( returnProtocolMessage == null )
					throw new MxitTransceiverException( "A new ProtocolMessage was not created successfully for the response. Response code: " + tempOuterStrArr[0] );
			}
			
			string[][] responseArr;
			
			if ( isBinaryData ) {
				log.Debug( "Multimedia message being populated" );
				// This is chunked binary data for a multimedia message ( command number 27 )
				responseArr = new string[3][];
				
				// Get command number
				responseArr[0] = new string[1];
				responseArr[0][0] = tempOuterStrArr[0];
				
				// Get the response error code and error message
				string[] tempInnerString = tempOuterStrArr[1].Split();
				responseArr[1] = new string[ tempInnerString.Length ];
				responseArr[1][0] = tempInnerString[0];
				if ( tempInnerString.Length == 2 )
					responseArr[1][1] = tempInnerString[1];
				
				// Get the chunked data
				responseArr[2] = new string[1];
				responseArr[2][0] = packet.Substring( tempOuterStrArr[0].Length + tempOuterStrArr[1].Length + 2 );
				
			}
			else {
				// Populate a jagged string array with the response.
				// Rows are delimited by \0 and individulal fields ( columns ) by \1
				responseArr = new string[ tempOuterStrArr.Length ][];
				for ( int i = 0; i < tempOuterStrArr.Length; ++i ){
					string[] tempInnerStrArr = tempOuterStrArr[i].Split( ( char ) 1 );
					responseArr[i] = new string[ tempInnerStrArr.Length ];
					
					for ( int j = 0; j < tempInnerStrArr.Length; ++j ){
						responseArr[i][j] = tempInnerStrArr[j];
						//Console.WriteLine( tempInnerStrArr[j] );
					}
				}
			}
			
			//log.Debug( responseArr );
			
			// Set the response variables in the message
			returnProtocolMessage.SetResponse( responseArr );
			
			return returnProtocolMessage;
		}
		
		private ProtocolMessage PopulateMessage( string packet ) {
			return PopulateMessage( packet, null );
		}
		
	}
}
